package com.liry.security.config;

import com.liry.security.domain.AuthConstant;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

/**
 * 主要用来拦截token的
 * <p>
 * 这里构造器我需要注入authenticationManager ,但是这个类在SecurityConfig里注入，所有我只有在用到的地方手动注入
 *
 * @author ALI
 * @since 2023/6/4
 */
public class CustomHeaderAuthFilter extends BasicAuthenticationFilter {

    private CacheManager cacheManager;

    public CustomHeaderAuthFilter(AuthenticationManager authenticationManager,
                                  AuthenticationEntryPoint authenticationEntryPoint, CacheManager cacheManager) {
        super(authenticationManager, authenticationEntryPoint);
        this.cacheManager = cacheManager;
    }

    private void doParse(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
        try {
            // 这个步骤是将redis的信息设置到security上下文
            if (header.startsWith("Bearer")) {
                String token = header.replace("Bearer ", "");
                CustomUser user = cacheManager.get(AuthConstant.buildLoginKey(token), CustomUser.class);
                if (user == null) {
                    throw new AccountExpiredException("token无效！");
                }
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(user,
                                                                                                        user.getPassword(),
                                                                                                        user.getAuthorities());
                // 设置的上下文
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        } catch (Exception e) {
            // 抛出 AuthenticationException AccessDeniedException 两个类型的异常给 ExceptionTranslationFilter
            throw new AccountExpiredException("登录失败！");
        }
        chain.doFilter(request, response);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                    FilterChain filterChain) throws ServletException, IOException {
        String authorization = httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION);
        // 无token，和登录的走默认的逻辑
        // 还有被忽略的api
        if (httpServletRequest.getRequestURI().contains("/login") || httpServletRequest.getRequestURI().contains("/test")) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }
        this.doParse(httpServletRequest, httpServletResponse, filterChain);
    }
}
